package com.tff.gmall.manger.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.tff.gmall.RedisUtil;
import com.tff.gmall.beans.PmsSkuAttrValue;
import com.tff.gmall.beans.PmsSkuImage;
import com.tff.gmall.beans.PmsSkuInfo;
import com.tff.gmall.beans.PmsSkuSaleAttrValue;
import com.tff.gmall.manger.mapper.PmsSkuAttrValueMapper;
import com.tff.gmall.manger.mapper.PmsSkuImageMapper;
import com.tff.gmall.manger.mapper.PmsSkuInfoMapper;
import com.tff.gmall.manger.mapper.PmsSkuSaleAttrValueMapper;
import com.tff.gmall.service.PmsSkuInfoService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;

import java.util.List;
import java.util.UUID;

@Service
public class PmsSkuInfoServiceImpl implements PmsSkuInfoService {

    @Autowired
    private PmsSkuInfoMapper pmsSkuInfoMapper;
    @Autowired
    private PmsSkuImageMapper pmsSkuImageMapper;
    @Autowired
    private PmsSkuSaleAttrValueMapper pmsSkuSaleAttrValueMapper;
    @Autowired
    private PmsSkuAttrValueMapper pmsSkuAttrValueMapper;

    RedisUtil redisUtil = new RedisUtil();

    @Override
    public Integer saveSkuInfo(PmsSkuInfo pmsSkuInfo) {

        //商品sku保存
        Integer i = pmsSkuInfoMapper.savePmsSkuInfo(pmsSkuInfo);

        List<PmsSkuAttrValue> skuAttrValueList = pmsSkuInfo.getSkuAttrValueList();
        //平台属性值保存
        for (PmsSkuAttrValue pmsSkuAttrValue : skuAttrValueList) {
            //设置skuId
            pmsSkuAttrValue.setSkuId(pmsSkuInfo.getId());
            Integer v = pmsSkuAttrValueMapper.savePmsSkuAttrValue(pmsSkuAttrValue);

        }

        List<PmsSkuSaleAttrValue> skuSaleAttrValueList = pmsSkuInfo.getSkuSaleAttrValueList();
        //商品销售属性值保存
        for (PmsSkuSaleAttrValue pmsSkuSaleAttrValue : skuSaleAttrValueList) {
            pmsSkuSaleAttrValue.setSkuId(pmsSkuInfo.getId());
            Integer p = pmsSkuSaleAttrValueMapper.savePmsSkuSaleAttrValue(pmsSkuSaleAttrValue);
        }

        List<PmsSkuImage> skuImageList = pmsSkuInfo.getSkuImageList();
        //商品sku图片保存
        for (PmsSkuImage pmsSkuImage : skuImageList) {
            pmsSkuImage.setSkuId(pmsSkuInfo.getId());
            Integer integer = pmsSkuImageMapper.savePmsSkuImage(pmsSkuImage);
        }
        return i;
    }

    /***
     * 根据skuId查询商品sku
     * @param skuId
     * @return
     */
    @Override
    public PmsSkuInfo getPmsSkuInfoBySkuId(String skuId,String ip) {
        System.out.println("ip为"+ip+"的测试："+Thread.currentThread().getName()+"进入了商品详情也页");
        PmsSkuInfo pmsSkuInfo = new PmsSkuInfo();
        //链接缓存
        Jedis redis = redisUtil.getRedis();
        //查询缓存
        String key = "sku:"+skuId+":info";
        String skuinfo = redis.get(key);
        if(StringUtils.isNotBlank(skuinfo)){
            System.out.println("ip为"+ip+"的测试："+Thread.currentThread().getName()+"从缓存中获取商品详情页");
             pmsSkuInfo = JSON.parseObject(skuinfo, PmsSkuInfo.class);
        }else {
            System.out.println("ip为"+ip+"的测试："+Thread.currentThread().getName()+"发现缓存中没有，获取分布式锁"+"sku"+skuId+"lock");
            //为了防止获得redis锁过期之后删除其他线程的锁
            String token = UUID.randomUUID().toString();
            //设置分布式锁
            String ok = redis.set("sku" + skuId + "lock", token, "nx", "px", 10*1000);
            if(StringUtils.isNotBlank(ok) && ok.equals("OK")){
                System.out.println("ip为"+ip+"的测试："+Thread.currentThread().getName()+"成功拿到锁，在10秒之内访问数据库");
                //设置成功，有权在10s的时间范围内访问数据库
                //如果缓存中没有再去查询musql
                pmsSkuInfo = pmsSkuInfoMapper.getPmsSkuInfoBySkuId(skuId);
              /*  try {
                    //Thread.sleep(10*1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
                if (pmsSkuInfo != null){
                    //mysql查询结果存入redis
                    System.out.println("ip为"+ip+"的测试："+Thread.currentThread().getName()+"从缓存中获取商品详情页");
                    redis.set("sku:"+skuId+":info",JSON.toJSONString(pmsSkuInfo));
                }else {
                    //数据库中不存在sku
                    //为了防止缓存穿透，将null或者空值设置给redis
                    redis.setex("sku:"+skuId+":info",60*3,JSON.toJSONString(""));
                }
                //为了防止获得redis锁过期之后删除其他线程的锁
                String lockToken = redis.get("sku" + skuId + "lock");

                if(StringUtils.isNotBlank(lockToken) && lockToken.equals(token)){
                    /*
                        if外层redis还没有删除，进入到判断以后正要删除时，redis锁过期了，这种情况下，也有可能删除别人的锁，
                        所以，我们在获取key的时候，只要获取到就删除他。用lua脚本解决此问题
                     */
                    //访问完数据库以后要将分布式锁释放掉，要不别人没法访问
                    redis.del("sku" + skuId + "lock");
                    System.out.println("ip为"+ip+"的测试："+Thread.currentThread().getName()+"将锁归还");
                }


            }else {
                System.out.println("ip为"+ip+"的测试："+Thread.currentThread().getName()+"没拿到锁，开始自旋");
                //分布式锁设置失败,自旋（该线程在沉睡几秒后，重新尝试访问本方法）
                /*try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
                /***
                 * 错误自旋的方法，如果方法前面不加 return 会在开启一个线程
                 *  getPmsSkuInfoBySkuId(skuId);
                 */
                return getPmsSkuInfoBySkuId(skuId,ip);
            }

        }

        //redis 用完之后就关闭了
        redis.close();
        return pmsSkuInfo;
    }

    /***
     * 根据当前的spu查询sku及sku所对应的属性值列表
     * @param productId
     * @return
     */
    @Override
    public List<PmsSkuInfo> getSkuSaleAttrValueListBySpu(String productId) {
        List<PmsSkuInfo> pmsSkuInfos = pmsSkuInfoMapper.selectSkuSaleAttrValueListBySpu(productId);
        return pmsSkuInfos;
    }

    /***
     * 查询所有的skuinfo
     * @return
     */
    @Override
    public List<PmsSkuInfo> getPmsSkuInfos() {
        return pmsSkuInfoMapper.selectPmsSkuInfos();
    }
}
